﻿using System;
using System.Data;

namespace HW3
{
    class CalcTable
    {
        Random rnd = new Random();
        private Prop prop;

        public int OrderMaxCondition { get; set; }

        public CalcTable(Prop prop)
        {
            this.prop = prop;
        }

        protected int GetRandomInt(int min, int max)
        {
            return rnd.Next(min, max);
        }

        public void CreateTable()
        {
            prop.AdditionalTempRandomTable = new DataTable();
            for (var i = 0; i < prop.TimeLength; i++)
            {
                int myInt = GetRandomInt(1, 99);
                try
                {
                    prop.AdditionalTempRandomTable.Columns.Add(myInt.ToString());
                    addValus(myInt, i);
                }
                catch (Exception)
                {
                    i--;
                }
            }
        }

        private void addValus(int myInt, int col)
        {
            for (int i = 0; i < prop.DataTable1.Rows.Count; i++)
            {
                if (col == 0)
                {
                    if (myInt >= int.Parse(prop.DataTable1.Rows[i][4].ToString()) && myInt <= int.Parse(prop.DataTable1.Rows[i][5].ToString()))
                    {
                        prop.AdditionalTempRandomTable.Rows.Add(prop.DataTable1.Rows[i][0].ToString());
                    }
                    else
                    {
                        prop.AdditionalTempRandomTable.Rows.Add(0);
                    }
                }
                else
                {
                    if (myInt >= int.Parse(prop.DataTable1.Rows[i][4].ToString()) && myInt <= int.Parse(prop.DataTable1.Rows[i][5].ToString()))
                    {
                        prop.AdditionalTempRandomTable.Rows[i][col] = prop.DataTable1.Rows[i][0].ToString();
                    }
                    else
                    {
                        prop.AdditionalTempRandomTable.Rows[i][col] = 0;
                    }
                }
            }
        }

        public bool SimaluationTable(int orderMaxCondition)
        {
            bool flag = false;
            OrderMaxCondition = orderMaxCondition;
            progerss pBar = new progerss();
            double tempDailyOutcomeAvg=0;
            prop.AverageAmountOfLosses = 0;
            prop.AverageAmountOfOrders = 0;
            pBar.SetMaxValue(prop.QuantitySimulation);
            pBar.Show();

            double[] avg = new double[3];

            for (var j=0 ; j < prop.QuantitySimulation;j++ ){
                pBar.UpdateProgress(j);
                pBar.UpdateLabel(  j.ToString()+"/"+prop.QuantitySimulation );

                prop.SimaluationTable.Clear();
                CreateTable();
            for (var i = 0; i < prop.TimeLength; i++){
                if (i == 0){
                    FirstRow();
                }
                else{
                    CalcRow(i);
                }
            }
                CalcTotal(ref avg);
                prop.DailyOutcome[j] = CalcDailyOutcome(avg);
                prop.AverageAmountOfLosses += avg[1];
                prop.AverageAmountOfOrders += avg[2];
                tempDailyOutcomeAvg += prop.DailyOutcome[j];
                if(j==99){
                    tempDailyOutcomeAvg = tempDailyOutcomeAvg / prop.QuantitySimulation;
                    prop.AverageAmountOfLosses = prop.AverageAmountOfLosses /prop.QuantitySimulation;
                    prop.AverageAmountOfOrders = prop.AverageAmountOfOrders / prop.QuantitySimulation;
                }
                if (tempDailyOutcomeAvg < prop.DailyOutcomeAvg && j == 99 || prop.DailyOutcomeAvg==0)
                {
                    prop.DailyOutcomeAvg = tempDailyOutcomeAvg;
                    flag = true;
                }
            }
            pBar.Hide();
            return flag;
            
        }

        private double CalcDailyOutcome(double[] avg)
        {
            double ret=avg[2]*prop.OrderPrice + avg[0]*prop.StorePrice + avg[1]*prop.LostPrice;
            return ret;
        }

        private void CalcTotal(ref double[] avg)
        {
            double left = 0;
            double sellsLost = 0;
            double orderOrNot = 0;
            
            for (var i = 0; i < prop.SimaluationTable.Rows.Count; i++)
            {
                left += int.Parse(prop.SimaluationTable.Rows[i]["Left"].ToString());
                sellsLost += int.Parse(prop.SimaluationTable.Rows[i]["Sells lost"].ToString());
                if (prop.SimaluationTable.Rows[i]["Order or not"].ToString().Equals("yes"))
                    orderOrNot++;
            }
            avg[0] = left / prop.TimeLength;
            avg[1] = sellsLost / prop.TimeLength;
            avg[2] = orderOrNot / prop.TimeLength;
        }

        private void CalcRow(int j)
        {
            prop.SimaluationTable.Rows.Add();

            prop.SimaluationTable.Rows[j]["Month"] = j + 1;
            prop.SimaluationTable.Rows[j]["Income"] = GetIncome(j);
            prop.SimaluationTable.Rows[j]["Storage"] = GetStorage(j);
            prop.SimaluationTable.Rows[j]["Random number1"] = prop.AdditionalTempRandomTable.Columns[j].ColumnName;
            prop.SimaluationTable.Rows[j]["Bought"] = GetBought(j);
            prop.SimaluationTable.Rows[j]["Left"] = GetLeft(j);
            prop.SimaluationTable.Rows[j]["Sells lost"] = GetSellsLost(j);
            prop.SimaluationTable.Rows[j]["Order or not"] = GetOrderOrNot(j, OrderMaxCondition);
            prop.SimaluationTable.Rows[j]["Random number2"] = GetRandomInt(1, 100);
            prop.SimaluationTable.Rows[j]["Delivery"] = GetDelivery(j);
            prop.SimaluationTable.Rows[j]["Waiting delivery"] = GetWaitingDelivery(j);
        }

        private void FirstRow()
        {
            prop.SimaluationTable.Rows.Add();

            prop.SimaluationTable.Rows[0]["Month"] = 1;
            prop.SimaluationTable.Rows[0]["Income"] = 0;
            prop.SimaluationTable.Rows[0]["Storage"] = prop.InitialAmount;
            prop.SimaluationTable.Rows[0]["Random number1"] = prop.AdditionalTempRandomTable.Columns[0].ColumnName;
            prop.SimaluationTable.Rows[0]["Bought"] = GetBought(0);
            prop.SimaluationTable.Rows[0]["Left"] = GetLeft(0);
            prop.SimaluationTable.Rows[0]["Sells lost"] = GetSellsLost(0);
            prop.SimaluationTable.Rows[0]["Order or not"] = GetOrderOrNot(0, OrderMaxCondition);
            prop.SimaluationTable.Rows[0]["Random number2"] = GetRandomInt(1, 100);
            prop.SimaluationTable.Rows[0]["Delivery"] = GetDelivery(0);
            prop.SimaluationTable.Rows[0]["Waiting delivery"] = GetWaitingDelivery(0);
        }

        private string GetStorage(int j)
        {
            int ret = int.Parse(prop.SimaluationTable.Rows[j]["Income"].ToString());
            ret += int.Parse(prop.SimaluationTable.Rows[j - 1]["Left"].ToString());
            return ret.ToString();
        }

        private string GetOrderOrNot(int row, int orderMaxCondition)
        {
            if (row == 0)
            {
                if (int.Parse(prop.SimaluationTable.Rows[row]["Left"].ToString()) < orderMaxCondition)
                {
                    return "yes";
                }
                else
                {
                    return "no";
                }
            }
            else
            {
                if (int.Parse(prop.SimaluationTable.Rows[row]["Left"].ToString()) < orderMaxCondition &&
                    prop.SimaluationTable.Rows[row - 1]["Order or not"].Equals("no"))
                {
                    return "yes";
                }
            }
            return "no";
        }

        private string GetWaitingDelivery(int row)
        {
            if (row == 0)
            {
                if (prop.SimaluationTable.Rows[row]["Order or not"].ToString().Equals("yes") &&
                    prop.SimaluationTable.Rows[row]["Income"].ToString().Equals("0")){
                    return "yes";
                }
                return "no";
            }
            else
            {
                if(prop.SimaluationTable.Rows[row-1]["Waiting delivery"].ToString().Equals("yes") &&
                    prop.SimaluationTable.Rows[row]["Income"].ToString().Equals("0"))
                {
                    return "yes";
                }
                return prop.SimaluationTable.Rows[row]["Order or not"].ToString();
            }
        }

        private string GetDelivery(int row)
        {
            var rand = int.Parse(prop.SimaluationTable.Rows[row]["Random number2"].ToString());
            if (prop.SimaluationTable.Rows[row]["Order or not"].ToString().Equals("yes"))
            {
                for (var i = 0; i < prop.DataTable2.Rows.Count; i++)
                {
                    var lower = int.Parse(prop.DataTable2.Rows[i]["Lower"].ToString());
                    var upper = int.Parse(prop.DataTable2.Rows[i]["Upper"].ToString());
                    if (rand <= upper && rand >= lower)
                    {
                        int ans = i + 1;
                        return ans.ToString();
                    }
                }
            }
            return "0";
        }

        private string GetSellsLost(int row)
        {
            int sum = int.Parse(prop.SimaluationTable.Rows[row]["Storage"].ToString());
            sum -= int.Parse(prop.SimaluationTable.Rows[row]["Bought"].ToString());

            if (sum > 0)
            {
                return "0";
            }
            sum = Math.Abs(sum);
            return sum.ToString();
        }

        private string GetLeft(int row)
        {
            int sum = int.Parse(prop.SimaluationTable.Rows[row]["Storage"].ToString());
            sum -= int.Parse(prop.SimaluationTable.Rows[row]["Bought"].ToString());
            if(sum<0)
            {
                return "0";
            }
            return sum.ToString();
        }

        private string GetBought(int row)
        {
            int sum = 0;
            for (var i = 0; i < prop.AdditionalTempRandomTable.Rows.Count; i++)
            {
                int num = int.Parse(prop.AdditionalTempRandomTable.Rows[i][row].ToString());
                sum += num;
            }
            return sum.ToString();
        }

        private string GetIncome(int row)
        {
            switch (row)
            {
                case 1:
                    return "0";
                case 2:
                    if (prop.SimaluationTable.Rows[0]["Delivery"].ToString().Equals("1"))
                    {
                        return CalcIncome(row);
                    }
                    return "0";
                case 3:
                    if (prop.SimaluationTable.Rows[1]["Delivery"].ToString().Equals("1") || 
                        prop.SimaluationTable.Rows[0]["Delivery"].ToString().Equals("2"))
                    {
                        return CalcIncome(row);
                    }
                    return "0";
                case 4:
                    if (prop.SimaluationTable.Rows[0]["Delivery"].ToString().Equals("3") || 
                        prop.SimaluationTable.Rows[1]["Delivery"].ToString().Equals("2") || 
                        prop.SimaluationTable.Rows[2]["Delivery"].ToString().Equals("1"))
                    {
                        return CalcIncome(row);
                    }
                    return "0";
                default:
                    if (prop.SimaluationTable.Rows[row-5]["Delivery"].ToString().Equals("4") ||
                        prop.SimaluationTable.Rows[row-4]["Delivery"].ToString().Equals("3") ||
                        prop.SimaluationTable.Rows[row-3]["Delivery"].ToString().Equals("2") ||
                        prop.SimaluationTable.Rows[row-2]["Delivery"].ToString().Equals("1"))
                    {
                        return CalcIncome(row);
                    }
                    return "0";
            }
        }

        private string CalcIncome(int row)
        {
            var left = int.Parse(prop.SimaluationTable.Rows[row - 1]["Left"].ToString());
            var income = 0;
            var up = 0;
            CalculationOfOrders stg = new CalculationOfOrders(prop.OrderSize[0], prop.OrderSize[1]);
            for (int i = 0; i < 8; i++)
            {
                stg.BuildIndexCalculation(up + 1);
                income = stg.CheckAmountInCalculation(left);
                if (income == 0)
                {
                    up++;
                }
                else
                {
                    i = 9;
                }
            }
            return income.ToString();
        }
    
    }
}
